iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0

目前畫面上的地區是固定的,但我們這個 App 是要顯示目前所在地區的天氣,所以這篇文章會示範如何取得目前所在地區的資料,並且顯示在畫面上。

如何取得目前所在地區名稱

目前我們已經透過 Expo Location 來取得目前所在地區的經緯度,不過只有經緯度還不夠,我們還需要透過經緯度來取得地區名稱,這裡會使用到 Geocoding API 來反向取得地區名稱。

詳細的申請流程可以參考 這篇我寫的文章

新增 API URL 以及 API Key

取得 Geocoding API 的 URL 以及 API Key 後,我們要把它們放到 .env 檔案中方便使用:

EXPO_PUBLIC_GEOCODING_API_KEY=輸入你的 API Key
EXPO_PUBLIC_GEOCODING_API_URL=https://maps.googleapis.com/maps/api/geocode/json?

新增 API 方法以及狀態

因為前面已經用 Zustand 做好狀態管理,所以現在要新增方法非常方便,只要在 store/index.ts 新增有關 city 的狀態還有 API 即可:

interface AddressComponent {
  long_name: string;
  short_name: string;
  types: string[];
}

interface LocationResult {
  address_components: AddressComponent[];
}

interface Store {
  location: Location.LocationObject | null
  errorMsg: string | null
  currentWeather: CurrentWeatherInfo | null
  city: string | null
  setCity: (city: string | null) => void
  setLocation: (location: Location.LocationObject | null) => void
  setErrorMsg: (msg: string | null) => void
  setCurrentWeather: (weather: CurrentWeatherInfo | null) => void
  fetchWeatherData: () => Promise<void>
  fetchLocation: () => Promise<void>
}

const useStore = create<Store>((set) => ({
  location: null,
  errorMsg: null,
  currentWeather: null,
  city: null,
  setCity: (city) => set({ city }),
  setLocation: (location) => set({ location }),
  // 省略其他程式碼
  fetchLocation: async () => {
    const { location } = useStore.getState()

    if (location && location.coords) {
      const { latitude, longitude } = location.coords
      const apiUrl = process.env.EXPO_PUBLIC_GEOCODING_API_URL
      const apiKey = process.env.EXPO_PUBLIC_GEOCODING_API_KEY

      try {
        const res = await fetch(
          `${apiUrl}latlng=${latitude},${longitude}&key=${apiKey}&language=en`
        )
        const json = await res.json()
        const cityComponent = json.results
          .flatMap((result: LocationResult) => result.address_components)
          .find((component: AddressComponent) => component.types.includes('locality'))

        if (cityComponent) {
          useStore.getState().setCity(cityComponent.long_name)
        } else {
          console.error('City name not found')
        }
      } catch (err) {
        console.log(err)
      }
    }
  }
}))

呼叫 API

接下來在 App.tsx 中呼叫 API:

export default function App() {
  const { location, errorMsg, setLocation, setErrorMsg, fetchWeatherData, fetchLocation } = useStore()

  // 省略其他程式碼

  useEffect(() => {
    if (location) {
      fetchWeatherData()
      fetchLocation()
    }
  }, [location])

  return (
    <SafeAreaView className='flex-1 bg-blue-500'>
      // 省略其他程式碼
    </SafeAreaView>
  )
}

location 有值時,就會呼叫 fetchLocation 方法,這樣就可以取得目前所在地區的名稱了。

顯示目前地區

最後在 HeadInfo.tsx 中顯示目前地區:

import { View, Text } from 'react-native'
import useStore from '../store'

const HeaderInfo = () => {
  const { city } = useStore()
  return (
    <View className='items-center p-6 space-y-4 w-500'>
      <Text className='text-2xl font-semibold text-white'>{city}</Text>
      <Text className='text-sm text-gray-200'>Monday, 12 September</Text>
    </View>
  )
}

可以測試一下 Custom Location,觀察目前地區是否有變化。

20231004005357

這篇文章展示了如何將 Expo Location 取得的經緯度,透過 Geocoding API 的應用來取得目前所在地區的名稱,明天來處理現在時間的顯示,明天見👋!


上一篇
Day 21 - 使用 Zustand 管理狀態
下一篇
Day 23 - 顯示現在時間
系列文
掌握 React Native 與 Expo:30天雙打,新手也能精通跨平台開發!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言